﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Casamiel.Common.Utilities
{
	/// <summary>
	/// 加密解密工具类
	/// </summary>
	public static class SecurityUtil
	{
		/// <summary>
		/// 加密
		/// </summary>
		/// <param name="input"></param>
		/// <param name="key">长度要大于8</param>
		/// <returns></returns>
		public static string EncryptText(string input, string key)
		{
			if (key == null) {
				throw new ArgumentNullException(nameof(key));
			}
			if (key.Length < 8) {
				throw new ArgumentNullException(nameof(key));
			}
			byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input);
			byte[] passwordBytes = Encoding.UTF8.GetBytes(key);

			passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

			byte[] bytesEncrypted = AESEncryptBytes(bytesToBeEncrypted, passwordBytes);

			string result = Convert.ToBase64String(bytesEncrypted);

			return result;
		}

		private static byte[] AESEncryptBytes(byte[] bytesToBeEncrypted, byte[] passwordBytes)
		{
			byte[] encryptedBytes = null;

			var saltBytes = new byte[9] { 13, 34, 27, 67, 189, 255, 104, 219, 122 };

			using (var ms = new MemoryStream()) {
				using (var AES = new RijndaelManaged()) {
					AES.KeySize = 256;
					AES.BlockSize = 128;

					var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
					AES.Key = key.GetBytes(32);
					AES.IV = key.GetBytes(16);

					AES.Mode = CipherMode.CBC;

					using (var cs = new CryptoStream(ms, AES.CreateEncryptor(),
						CryptoStreamMode.Write)) {
						cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
						cs.Close();
					}

					encryptedBytes = ms.ToArray();
				}
			}

			return encryptedBytes;
		}

		/// <summary>
		/// 解密
		/// </summary>
		/// <param name="input"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public static string DecryptText(string input, string key)
		{
			byte[] bytesToBeDecrypted = Convert.FromBase64String(input);

			byte[] passwordBytes = Encoding.UTF8.GetBytes(key);

			passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

			byte[] bytesDecrypted = AESDecryptBytes(bytesToBeDecrypted, passwordBytes);

			string result = Encoding.UTF8.GetString(bytesDecrypted);

			return result;
		}

		private static byte[] AESDecryptBytes(byte[] bytesToBeDecrypted, byte[] passwordBytes)
		{
			byte[] decryptedBytes = null;

			var saltBytes = new byte[9] { 13, 34, 27, 67, 189, 255, 104, 219, 122 };

			using (var ms = new MemoryStream()) {
				using (var AES = new RijndaelManaged()) {
					AES.KeySize = 256;
					AES.BlockSize = 128;

					var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
					AES.Key = key.GetBytes(32);
					AES.IV = key.GetBytes(16);

					AES.Mode = CipherMode.CBC;

					using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write)) {
						cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
						cs.Close();
					}

					decryptedBytes = ms.ToArray();
				}
			}

			return decryptedBytes;
		}
	}
}
